/** Clase NPC
 * Un NPC hablará al PJ en lo que llamaremos un diálogo (aunque realmente es un monólogo), que se compone
 * de diversas intervenciones. Para pasar de una intervención a otra hay que pulsar 'acción', cuando ya
 * no quedan intervenciones, se termina el diálogo.
 */

package source.Objetos 
{
    import flash.geom.Point;
    import net.flashpunk.Entity;
    import net.flashpunk.FP;
    import net.flashpunk.graphics.Image;
    import net.flashpunk.graphics.Spritemap;
    import net.flashpunk.graphics.Text;
    import net.flashpunk.tweens.motion.LinearMotion;
    import net.flashpunk.utils.Input;
    import source.Assets;
    import source.Global;

	public class NPC extends Entity	{
		public var sprite:Spritemap;
        
        //Variables relativas al estado en movimiento del NPC:
        public var movimiento:LinearMotion = new LinearMotion(finMovimiento);
        public var listaNodos:Array = new Array();
        public var nodoActual:uint = 0;
        public var velocidad:Number = 0;
        public var timerEsperandoMovimiento:uint = 0;
        public var enMovimiento:Boolean = false;
        public var direccionMovimiento:Boolean; //true = hacia la izquierda, false = hacia la derecha
        public var posAnterior:Point = new Point(); //la posición previa a la actual
        
		//Variables relativas al estado estático del NPC:
		public var timerEsperandoReorientacion:uint;
		public var direccionEncarar:Boolean = true; //true = hacia la izquierda, false = hacia la derecha
        
		//Variables relativas al "monógogo" del NPC:
		public var interactuable:Boolean = false; //si el NPC no tiene nada que decir, no será interactuable
		public var contenedorAdmiracion:Entity;   //entidad que contendrá la admiración
		public var contenedorVentana:Entity;      //entidad que contendrá la imagen de la ventana emergente para mostrar el diálogo
		public var contenedorPulsarAccion:Entity; //entidad que contendrá el texto "Pulsa 'acción' para continuar".
		public var listaIntervenciones:Array;     //array para almacenar y manejar las intervenciones del NPC
		public var numIntervencion:uint = 0;      //control para el índice del array de intervenciones
		private const token:String = '·';         //caracter utilizado para separar las intervenciones del diálogo
		
        /**
         * Constructor
         * @param	x
         * @param	y
         * @param	_dialogo
         * @param	_grafico
         * @param	_listaNodos
         * @param	_velocidad
         */
		public function NPC(x:int, y:int, _dialogo:String, _grafico:String, _listaNodos:Array, _velocidad:Number) {
			super(x, y);
            var i:int = 0; //contador para el control de los bucles
			
            //gráfico y hitbox:
			if (_grafico != "singrafico")
				sprite = new Spritemap(Assets[_grafico], 36, 50);
			else
				sprite = new Spritemap(Assets.NPC_DUMMY, 36, 50);
			setHitbox(15, 35, -6, -15);
			graphic = sprite;
            
            //animaciones estáticas:
			const frameRateEnPie:Number = 0.05;
			sprite.add("enPieDch", [8], frameRateEnPie, false);
            sprite.add("enPieIzq", [0], frameRateEnPie, false);
            
            //configuramos los nodos a los que se dirigirá el NPC, según lo definido desde el Ogmo Editor:
            if (_velocidad) {
                velocidad = _velocidad;
                listaNodos = _listaNodos;
                
                addTween(movimiento);
                
                //nos movemos hasta el nodo inicial (la posición inicial del NPC, en el ogmo realmente no es ningún nodo...):
                movimiento.setMotionSpeed(x, y, listaNodos[nodoActual].x, listaNodos[nodoActual].y, velocidad);
                finMovimiento();
                nodoActual++;
                
                //animaciones de caminar:
                const frameRateCaminar:Number = velocidad*0.1;
                sprite.add("caminarDch", [12, 13, 14, 15], frameRateCaminar, true);
                sprite.add("caminarIzq", [4, 5, 6, 7], frameRateCaminar, true);
            }
            
            //Configuramos el monólogo:
			if (_dialogo != "sintexto")
				interactuable = true;
			if (interactuable) {
				//Configuramos la admiración y la posicionamos encima del NPC:
				var _admiracion:Text = new Text("!");
				_admiracion.size = 28;
                _admiracion.font = "ModernAntiqua";
				contenedorAdmiracion = new Entity(0, 0, _admiracion);
				contenedorAdmiracion.x = x + Global.grid/2 - _admiracion.textWidth/2;
				contenedorAdmiracion.y = y - _admiracion.textHeight;
				
				//Configuramos la ventana emergente:
				const _coordX:uint = FP.width/2 - 100;
				const _coordY:uint = FP.height / 2 - 75;
				contenedorVentana = new Entity(_coordX, _coordY, Image.createRect(200, 150, 0, 0.75));
				
				//Configuramos el texto "(pulsa 'accion' para continuar)":
				var _pulsarAccion:Text = new Text("(pulsa 'accion' para continuar)");
				_pulsarAccion.size = 8;
                _pulsarAccion.font = "ModernAntiqua";
				contenedorPulsarAccion = new Entity(_coordX + 33, _coordY + 135, _pulsarAccion);
				
				//Llenamos el array con la lista de intervenciones que componen el diálogo
				//('token' es un const string definido arriba, es el caracter delimitador
				//de cada intervención desde el Ogmo):
				listaIntervenciones = new Array();
				var _array:Array = _dialogo.split(token);
				Text.size = 11;
                Text.font = "ModernAntiqua";
				for (i = 0; i < _array.length; i++) {
					listaIntervenciones.push(new Entity(_coordX + 25,
														_coordY + 25,
														new Text(distribuirTexto(_array[i]))));
				}
			}
		}
		
        /**
         * update
         * Es llamado cada frame
         */
		override public function update():void {
            //Si el NPC se mueve, le "obligamos" a ir a un nodo aleatoriamente, según el desplazamiento que dicta el objeto movimiento de la clase LinearMotion:
            if (velocidad) {
                if (!timerEsperandoMovimiento && !enMovimiento) {
                    //Ordenamos al Tween LinearMotion que se ponga en movimiento:
                    movimiento.setMotionSpeed(x, y, listaNodos[nodoActual].x, listaNodos[nodoActual].y, velocidad);
                    enMovimiento = true;
                    
                    //Elegimos aleatoriamente el siguiente nodo, siempre que sea uno diferente del actual:
                    var num:uint = 0;
                    do num = Global.numAleat(0, listaNodos.length - 1); while (num == nodoActual);
                    nodoActual = num;
                }
                else
                    timerEsperandoMovimiento--;
                
                //Guardamos la posición actual:
                posAnterior.x = x;
                posAnterior.y = y;
                //Movemos el NPC:
                x = movimiento.x;
                y = movimiento.y;
                //Evaluamos la dirección de nuestro movimiento según las posiciones anterior y actual:
                if (posAnterior.x < x) direccionMovimiento = false;
                else direccionMovimiento = true;
                
                //actualizamos la posición de la admiración, si el NPC es interactuable, lo que hacemos es
                //desplazarla la misma distancia en que se desplazó el NPC (posición final - posición inicial):
                if (interactuable) {
                    contenedorAdmiracion.x -= posAnterior.x - x;
                    contenedorAdmiracion.y -= posAnterior.y - y;
                }
            }
            
			//Gestión y visualización del diálogo que tiene almacenado el NPC:
			if (interactuable) {
				if (collideWith(Global.pj, x, y)) { //Nota: collideWith() es más rápido que collide()
					if (Input.pressed("Accion")) {
						trace(listaIntervenciones.length);
						numIntervencion++;
						if (numIntervencion == 1) {
							world.add(contenedorVentana);
							world.add(contenedorPulsarAccion);
							world.add(listaIntervenciones[numIntervencion - 1]);
						}
						else if (listaIntervenciones.length == numIntervencion - 1) {
							world.remove(listaIntervenciones[numIntervencion - 2]);
							world.remove(contenedorVentana);
							world.remove(contenedorPulsarAccion);
							numIntervencion = 0;
                            if (velocidad && !movimiento.active) movimiento.active = true; //si el NPC tiene la capacidad de moverse, le desparalizamos
						}
						else if (numIntervencion > 1) {
							world.remove(listaIntervenciones[numIntervencion - 2]);
							world.add(listaIntervenciones[numIntervencion - 1]);
						}
					}
					
					if (!numIntervencion) {
						world.add(contenedorAdmiracion);
						Global.pj.paralizado = false;
					}
					else {
						world.remove(contenedorAdmiracion);
						Global.pj.paralizado = true;
                        if (velocidad) movimiento.active = false; //si el NPC tiene la capacidad de moverse, le paralizamos
					}
				}
				else world.remove(contenedorAdmiracion);
			}
			
			//Gestión de las animaciones del NPC:
            if (!enMovimiento) {
                if (!timerEsperandoReorientacion) {
                    if (direccionEncarar) sprite.play("enPieIzq");
                    else sprite.play("enPieDch");
                    direccionEncarar = !direccionEncarar;
                    timerEsperandoReorientacion = Global.numAleat(Global.npcTiempoMinReorientacion, Global.npcTiempoMaxReorientacion); //tiempos ajustables desde Global
                }
                else
                    timerEsperandoReorientacion--;
            }
            else if (!movimiento.active) {
                if (direccionMovimiento) sprite.play("enPieIzq");
                else sprite.play("enPieDch");
            }
            else {
                if (direccionMovimiento) sprite.play("caminarIzq");
                else sprite.play("caminarDch");
            }
		}
		
		/**
		 * distribuirTexto
		 * @param	_texto
		 * @return
         * 
         * Este método distribuirá el texto en líneas de 'num' caracteres con wordwrap
		 */
		public function distribuirTexto(_texto:String):String {
			var _aux1:String, _aux2:String;
			const num:int = 30;
			
			_aux2 = _texto;
			_aux1 = _aux2;
			_texto = "";
			
			while (_aux2.length > num) {				
				for (var i:int = _aux2.length; i >= 0; i--) { //recorremos la cadena al revés: desde el final hasta el principio
					//separamos en dos trozos sólo si el primero mide 'num' o menos y siempre y cuando cortemos por un espacio:
					if ((_aux2.charAt(i) == ' ') && (i <= num)) {
						_aux1 = _aux2.slice(0, i);
						_aux2 = _aux2.slice(i+1, _aux2.length);
						break; //hecha la separación, salimos del bucle
					}
				}
				
				_texto = _texto.concat(_aux1 + "\n"); //Concateno la primera cadena y un retorno de carro en el texto
			}
			
			//concateno lo que sobra y retorno todo:
			return _texto.concat(_aux2 + "\n "); //introduzco el "\n " porque si no no funciona y no sé porqué... he aquí una ñapa wena wena
		}
        
        /**
         * finMovimiento
         * Se llama a este método cuando el movimiento del NPC ha terminado
         */
        public function finMovimiento():void {
            timerEsperandoMovimiento = Global.numAleat(Global.npcTiempoMinMoverse, Global.npcTiempoMaxMoverse); //tiempos ajustables desde Global
            enMovimiento = false;
            timerEsperandoReorientacion = 0;
        }
	}
}